package com.qinke.outtocluster;

import com.ibm.mq.*;
import com.ibm.mq.constants.MQConstants;
import com.qinke.mqcluster.utils.ConfigUtil;

import java.io.IOException;

public class CCQMReceiver {
    private static String host;
    private static Integer port;
    private static String channel;
    private static String qmgr;
    private static String asyncQueueName;
    private static String syncQueueName;

    private static void init() {
        host = ConfigUtil.getConfig("HOST");
        port = Integer.valueOf(ConfigUtil.getConfig("PORT"));
        channel = ConfigUtil.getConfig("CHANNEL");
        qmgr = ConfigUtil.getConfig("QMGR");
        asyncQueueName = ConfigUtil.getConfig("ASYNCQUEUE");
        syncQueueName = ConfigUtil.getConfig("SYNCQUEUE");
        StringBuffer lisLog = new StringBuffer();
        lisLog.append(host)
                .append(" : ")
                .append(port)
                .append(" : ")
                .append(channel)
                .append(" : ")
                .append(qmgr)
                .append(" : ")
                .append(asyncQueueName)
                .append(" : ")
                .append(syncQueueName);
        //配置要使用的队列管理器的信息，这里使用队列管理器CQM1的信息
        MQEnvironment.hostname = host;
        MQEnvironment.port = port;
        MQEnvironment.channel = channel;
        System.out.println("初始化");
        System.out.println("监听参数:" + lisLog.toString());
    }

    //异步消息接收
    private static void asyncReceive() {
        try {
            //创建队列管理器对象，在实例化的时候会隐式连接队列管理器CQM1
            MQQueueManager mqQueueManager = new MQQueueManager(qmgr);
            //定义打开方式
            int openOption = MQConstants.MQOO_INPUT_SHARED; //以读取方式打开
            //直接循环，每次发10条消息
            //创建队列对量
            MQQueue queue = mqQueueManager.accessQueue(asyncQueueName, openOption);
            //定义获取消息时的一些操作
            MQGetMessageOptions gmo = new MQGetMessageOptions();
            gmo.options = gmo.options + MQConstants.MQGMO_WAIT; //无消息时等待
            gmo.options = gmo.options + MQConstants.MQGMO_FAIL_IF_QUIESCING; //队列管理器停止时退出等待
            gmo.waitInterval = 300000; //无消息时等待时长
            System.out.println("异步队列开始监听");
            for (int i = 0; i <= 1000; i++) {
                //try-catch的目的是捕获获取消息超时抛出的异常，使程序能继续进行下一次获取消息，而不是整个程序直接退出
                try{
                    //创建简单消息对象
                    MQMessage mqMessage = new MQMessage();
                    queue.get(mqMessage, gmo);
                    String msgContent = mqMessage.readUTF();
                    System.out.println(msgContent);
                }catch (Exception e){
                    e.printStackTrace();
                }
            }
            //关闭打开的资源，养成好习惯
            queue.close();
            mqQueueManager.disconnect();
        } catch (MQException e) {
            e.printStackTrace();
        }
    }

    //同步消息接收
    private static void syncReceive() {
        try {
            //创建队列管理器对象，在实例化的时候会隐式连接队列管理器CQM1
            MQQueueManager mqQueueManager = new MQQueueManager(qmgr);
            //定义打开方式
            int openOption = MQConstants.MQOO_INPUT_SHARED; //以读取方式打开
            //直接循环，每次发10条消息
            //创建队列对量
            MQQueue queue = mqQueueManager.accessQueue(syncQueueName, openOption);
            //定义获取消息时的一些操作
            MQGetMessageOptions gmo = new MQGetMessageOptions();
            gmo.options = gmo.options + MQConstants.MQGMO_SYNCPOINT;//在同步点控制下获取消息
            gmo.options = gmo.options + MQConstants.MQGMO_WAIT; //无消息时等待
            gmo.options = gmo.options + MQConstants.MQGMO_FAIL_IF_QUIESCING; //队列管理器停止时退出等待
            gmo.waitInterval = 300000; //无消息时等待时长
            System.out.println("同步队列开始监听");
            /*
                这里为解决回执队列不同的情况，每次根据请求队列中携带的回执队列名称重新打开回执队列，若回执队列是确定的，可将回执队列的定义放到循环外，以减少队列开关次数来提高性能
             */
            for (int i = 0; i <= 1000; i++) {
                try {
                    //创建简单消息对象
                    MQMessage mqMessage = new MQMessage();
                    //接收消息
                    queue.get(mqMessage, gmo);
                    //读取消息内容
                    String msgContent = mqMessage.readUTF();
                    System.out.println(msgContent);
                    //判断，如果消息标识为请求消息，则进行回应
                    if (mqMessage.messageFlags == MQConstants.MQMT_REQUEST) {
                        //获取回应队列
                        String replyQueueName = mqMessage.replyToQueueName;
                        //获取回应队列管理器
                        String replyQueueManager = mqMessage.replyToQueueManagerName;
                        //使用回应队列，回应队列管理器创建回执消息队列的对象
                        MQQueue sendQueue = mqQueueManager.accessQueue(replyQueueName, MQC.MQOO_OUTPUT | MQC.MQOO_FAIL_IF_QUIESCING, null, null, null);
                        //创建回执消息对象
                        MQMessage sendMsg = new MQMessage();
                        //设置消息对应参数，发送端使用此参数进行消息关联
                        sendMsg.correlationId = mqMessage.messageId;
                        //将请求消息内容写入响应消息（按照自己的业务写入相应的数据，测试时为测试方便，将消息回写）
                        sendMsg.writeUTF(msgContent);
                        //设置消息类型为响应消息
                        sendMsg.messageFlags = MQConstants.MQMT_REPLY;
                        //消息发送
                        sendQueue.put(sendMsg);
                        mqQueueManager.commit();
                        //关闭发送队列
                        sendQueue.close();
                    }
                } catch(Exception e){
                    e.printStackTrace();
                }
            }
            //关闭打开的资源，养成好习惯
            queue.close();
            mqQueueManager.disconnect();
        } catch (MQException e) {
            e.printStackTrace();
        }
    }

    public static void main(String[] args) {
        init();
        syncReceive();
    }
}
